Canigó - Servei de Presentació (General) 2.1
SERVEI DE PRESENTACIÓ (GENERAL)
IntroduccióPropósitEl propósit d'aquest document és donar una visió general de quina és l'arquitectura base de la capa de presentació i els seus components, així com la configuració necessària.Es tractarà entre d'altres:
Context i Escenaris d'ÚsEls serveis de presentació es troben dins la Capa de Presentació definida a la partició en 3 capes de canigo. Versions i DependènciesLes dependències descrites a la següent url son requerides per tal de compilar i fer funcionar el projecte: A qui va dirigitAquest document va dirigit als següents perfils:
Documents i Fonts de Referència
GlossariPOJO (Plain Old Java Object) S'utilitza per anomenar classes que són ordinàries, és a dir no implementa cap interfície ni extén cap classe d'un framework concret. Tot i que s'apropa molt al terme 'JavaBeans' es tracta d'un terme més atractiu pel fet que el nom "bean" dóna lloc a un conflicte entre 2 termes totalment diferents com són 'JavaBeans' i 'Enterprise Java Beans'. DAO (Data Access Object) Patró de disseny mitjançant un component proporciona una interfície entre l'aplicació i un o més dispositius d'emmagatzematge de dades (base de dades, fitxer, ...). Els Data Access Objects o DAOs són un patró de disseny J2EE. L'avantatge principal del seu ús és que l'objecte de negoci (Business Objects) no necessita conéixer el destí de la informació que manipula. En Java es poden usar per aillar l'aplicació de la tecnologia de persistència utilitzada (JDBC, JDO, EJBs, Hibernate, etc.). En cas de que es canvii la tecnologia de persistència no caldrà canviar cap part de l'aplicació de negoci. BO (Business Object) Els Business Objects (o BO) abstrauen les entitats del domini que utilitza l'aplicació. A vegades són anomenats 'Domain Objects'. Encapsulen les dades i el comportament associat a l'entitat que representen. Descripció DetalladaArquitectura i ComponentsEl propósit d'aquest apartat és mostrar quina és l'arquitectura del servei i els components que la composen. En aquest apartat es detallen els següents aspectes:
Arquitectura i Patrons d'ÚsA l'hora de definir les nostres aplicacions és important que es faci un ús coherent de varis patrons de disseny. El patró de disseny a considerar és el Model Vista Control- lador clàssic. Així, el Servei de Presentació està enfocat a la resolució dels components Vista i Control- lador, propis d'una capa de presentació. El model no ha de fer servir cap tecnologia concreta i es poden desenvolupar mitjançant classes planes o POJOs. La interacció entre l'acció i el negoci ha de ser totalment transparent dels objectes de presentació usats. És a dir, el negoci no ha de tractar amb paràmetres de tipus 'HttpServletRequest' o 'ActionForms', pel que és tasca de la capa de presentació fer la transformació entre els objectes de presentació i els de negoci. Qualsevol petició rebuda haurà de ser gestionada per classes de tipus 'Action'. Aquestes han d'heretar de la classe 'net.gencat.ctti.canigo.services.web.struts.DispatchActionSupport'. L'acció no ha de realitzar cap tractament de negoci, només aspectes de presentació. Així no es permet que l'acció pugui accedir a la base de dades de forma directa. Tota delegació l'ha de fer sobre objectes de negoci que gestionaran el tractament. Aquests objectes de negoci, poden, de forma adicional fer ús de classes DAO d'accés a la base de dades per a persistir els objectes de negoci o obtenir-los. Vinculació de l'Objecte de NegociUna de les parts més important de canigo és la utilizació dels objectes de negoci com a models de la nostra presentació (al contrari que Struts on es fan servir 'ActionForms' per a representar el nostre model i cal fer el pas entre aquests objectes i els objectes de negoci). Per a que les nostres accions sàpiguen quin tipus de classe és el que han de utilitzar cal configurar la propietat 'pojoClass').
<bean name="/accounts" class="net.gencat.ctti.canigo.samples.jactionServlet.struts.action.AccountAction"> <property name="pojoClass" value="net.gencat.ctti.canigo.samples.jactionServlet.model.Account" /> Tractament de les peticions WebEn aquest apartat s'explica quin és el flux que segueix una petició des de que arriba al contenidor del servidor d'aplicacions fins que és tractat per un component control- lador específic. El tractament d'una petició des d'un navegador inclou els següents pasos:
Servlet principal que rep les peticions
En rebre una petició amb el patró final '*.do' (patró utilitzat per Struts) detecta que el gestor associat és 'strutsWrappingController'
Servlet principal de Struts NOTA: Es recomana una lectura prèvia de 'http://struts.apache.org/struts-doc- 1.2.8/userGuide/index.html' per conéixer en detall cóm funciona Struts.
RequestProcessor de Struts al que es delega la petició. Cal recordar que Struts permet l'extensió del seu comportament mitjançant l'extensió del seu bàsic RequestProcessor.
Aquesta injecció es realitza amb el mecanisme genèric de Spring com si d'una classe normal es tractés.
<bean name="/accounts" parent="accountBaseDefinition"> <property name="valueListActionHelper"> <bean parent="valueListActionHelper"> <property name="listName"> <value>accountList</value> </property> <property name="tableId" value="ACCOUNT"/> </bean> </property> <property name="servletRequestDataBinderFactory" ref="servletRequestDataBinderFactory"/> <property name="logService" ref="loggingService"/> <property name="pojoClass" value="net.gencat.ctti.canigo.samples.jactionServlet.model.Account" /> <property name="accountBO" ref="accountBO"/> </bean> NOTA: Per a injectar-hi les propietats, el processador ha de conéixer en quin fitxer es realitzen les injeccions, per això es defineix en el fitxer 'web.xml' el paràmetres de context 'contextConfigLocation' <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/classes/spring/applicationContext.xml /WEB-INF/classes/spring/action-servlet.xml </param-value> </context-param> ConsuLtar 'http://static.springframework.org/spring/docs/1.2.x/reference/beans.html' per més referència del mecanisme d'injecció. Mitjançant aquest mecanisme hem eliminat la necessitat de que les nostres Action siguin 'thread-safe' (una de les restriccions de Struts). Una vegada obtinguda la instància 'Action' que tracta la petició, el processador consulta si s'ha definit la propietat 'pojoClass' de la Action (en la injecció l'haurem incorporat). Si és així, i aquí radica una de les diferències més importants amb el tractament tradicional de Struts, el processador canigo realitza la traducció dels paràmetres rebuts a la petició en atributs de l'objecte definit al 'pojoClass'. Per a fer aquesta traducció s'ajuda del 'servletRequestDataBinderFactory' que s'ha definit al Action.
<bean name="/accounts" parent="accountBaseDefinition"> ... <property name="servletRequestDataBinderFactory" ref="servletRequestDataBinderFactory"/> </bean> Mitjançant aquesta característica, eliminem un dels desavantatges de Struts (comentat prèviament) pel qual que no s'establia la política de translació des dels paràmetres de la petició (HttpServletRequest) a objectes Java comuns. Per a que des dels nostres Action poguem accedir a l'objecte populat, es fa ús de formularis de tipus 'SpringBindingActionForm'. L'ús d'aquests tipus, enlloc del tradicional 'ActionForm' de Struts, permet l'ús de objectes des dels tags clàssics de Struts (i per tant de l'extensió realitzada a canigo) sense necessitat de definir formularis cópia dels objectes de negoci.
<form-beans> <form-bean name="actionForm" type="net.gencat.ctti.canigo.services.web.struts.SpringBindingActionForm"/> </form-beans> La nostra acció, per tant farà ús d'aquest formulari: <action path="/accounts" name="actionForm" ... En aquest moment ja hem eliminat un altre dels desavantatges de Struts comentat prèviament en el que es feia palés que els ActionForms són estructures innecessàries per expressar el model.
El Action pot accedir a l'objecte populat mitjançant el mètode 'getTarget' del form:
SpringBindingActionForm actionForm = (SpringBindingActionForm) form; Account vo = (Account) actionForm.getTarget();
Aquest objecte ha estat declarat mitjançant injecció de Spring a la nostra Action
El nom de la pantalla és un nom lógic que correspon a un dels forwards definits al fitxer de configuració de l'acció (struts-config.xml).
<forward name="success" path="pages.accounts"/> En cas que el path de retorn no correspongui a una pàgina JSP, entra el mecanisme de pantalles definit pel Servei de Pantalles. En aquest cas, la pantalla és construída a partir de la definició realitzada al fitxer 'tiles-defs.xml'.
En el següent gràfic podem veure de forma resumida el procés descrit:
Components Control- ladorDins els components Control- lador trobem tots aquells elements que s'encarreguen de gestionar una petició i interaccionar amb les vistes que presentaran les dades del model a l'usuari. Es pot trobar tota la documentació JavaDoc y el codi font referent aquests components a les següents urls: JavaDoc: http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_0/canigo-services-web/apidocs/index.html Instal- lació i ConfiguracióConfiguració BàsicaParàmetres de context Fitxer de configuració: web.xml Ubicació proposada: <PROJECT_ROOT>/src/main/webapp/WEB-INF/web.xml En aquest apartat definirem els següents paràmetres:
Indicar les referències als fitxers de configuració 'action-servlet.xml', on definirem les configuracions de les accions de Struts, i el fitxer 'applicationContext.xml' on definirem la injecció dels altres objectes (negoci, daos, ...)
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/classes/spring/applicationContext.xml /WEB-INF/classes/spring/action-servlet.xml </param-value> </context-param> Filtres Fitxer de configuració: web.xml Ubicació proposada: <PROJECT_ROOT>/src/main/webapp/WEB-INF/web.xml
Aquest filtre s'encarrega de integrar el Servei Atributs:
<filter> <filter-name>Struts Locale Filter</filter-name> <filter-class> net.gencat.ctti.canigo.services.web.i18n.StrutsLocaleFilter </filter-class> </filter>
Aquest filtre s'encarrega de integrar el Servei Atributs:
<filter> <filter-name>JSTL Locale Filter</filter-name> <filter-class> net.gencat.ctti.canigo.services.web.i18n.JSTLLocaleFilter </filter-class> </filter>
Aquest filtre s'ha definir per integrar el Servei de Seguretat de forma que qualsevol petició sigui filtrada prèviament abans d'arribar a l'Action. Atributs:
Paràmetres d'inicialització:
<filter> <filter-name>Acegi Filter Chain Proxy</filter-name> <filter-class> net.sf.acegisecurity.util.FilterToBeanProxy </filter-class> <init-param> <param-name>targetClass</param-name> <param-value> net.sf.acegisecurity.util.FilterChainProxy </param-value> </init-param> </filter> Mapeig dels Filtres Fitxer de configuració: web.xml Ubicació proposada: <PROJECT_ROOT>/src/main/webapp/WEB-INF/web.xml En aquest apartat configurarem en quins casos s'apliquen els filtres
Definirem que s'activi el filtre 'Struts Locale Filter' en els següents casos:
Definirem que s'activi el filtre 'JSTL Locale Filter' en els mateixos casos anteriors:
<filter-mapping>
<filter-name>JSTL Locale Filter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>JSTL Locale Filter</filter-name>
<url-pattern>/dwr/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>JSTL Locale Filter</filter-name>
<url-pattern>*.pdf</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>JSTL Locale Filter</filter-name>
<url-pattern>*.xls</url-pattern>
</filter-mapping>
Definirem que s'activi el filtre per qualsevol url
<filter-mapping> <filter-name>Acegi Filter Chain Proxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> Listeners ![]() Fitxer de configuració: web.xml Ubicació proposada: <PROJECT_ROOT>/src/main/webapp/WEB-INF/web.xml <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <listener> <listener-class> net.gencat.ctti.canigo.services.web.context.AspectWerkzContextListener </listener-class> </listener> Per a més referència consultar 'http://www.springframework.org/docs/api/org/springframework/web/context/ContextLoaderListener.html' Servlets Fitxer de configuració: web.xml Ubicació proposada: <PROJECT_ROOT>/src/main/webapp/WEB-INF/web.xml En aquest apartat configurarem en quins casos s'apliquen els filtres definits prèviament
Atributs:
<servlet> <servlet-name>actionServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/classes/spring/action-servlet.xml </param-value> </init-param> <load-on-startup>2</load-on-startup> </servlet>
Atributs:
<servlet> <servlet-name>dwr-invoker</servlet-name> <servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/classes/dwr/dwr.xml</param-value> </init-param> </servlet> Mappings de urls i Servlets Fitxer de configuració: web.xml Ubicació proposada: <PROJECT_ROOT>/src/main/webapp/WEB-INF/web.xml En aquest apartat configurarem quins servlets s'usaran Definirem els mapejos dels patrons següents al servlet 'actionServlet':
Tal i com es mostra a continuació:
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.doc</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.report</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.xml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.xls</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>actionServlet</servlet-name>
<url-pattern>*.pdf</url-pattern>
</servlet-mapping>
Configuració de Struts Fitxer de configuració: struts-config.xml Ubicació proposada: <PROJECT_ROOT>/src/main/resources/struts/struts-config.xml Per a la integració amb Struts definirem els següents elements:
Com a processorClass cal indicar la classe ' 'ExtendedDelegatingTilesRequestProcessor' del package ' net.gencat.ctti.canigo.services.web.struts'
Referència al fitxer base de internacionalització. <message-resources parameter="i18n.applicationResources" null="false"/>
En aquest apartat es defineixen els plugins d'integració amb Tiles (Servei de Pantalles) i la integració amb Spring.
<plug-in className="org.apache.struts.tiles.TilesPlugin"> <set-property property="definitions-config" value="/WEB-INF/classes/struts/tiles-definitions.xml"/> </plug-in> <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/classes/spring/action-servlet.xml"/> </plug-in> Configuració del mapeig entre paràmetres Web i objectes negoci Dins la classe 'ExtendedDelegatingTilesRequestProcessor' es realitza un mapeig entre els paràmetres rebuts i l'objecte configurat a la propietat 'pojoClass' de l'acció. Els valors dels paràmetres rebuts són de tipus 'String' (dins el protocol HTTP). Fitxer de configuració: property-editors.xml Ubicació proposada: <PROJECT_ROOT>/src/main/resources/spring/property-editors.xml
En aquest apartat es poden definir editors específics de transformació entre tipus. Per defecte no cal definir els editors de transformació entre tipus bàsics (String a boolean, String a Integer, etc.) S'ofereixen els següents editors:
Package:net.gencat.ctti.canigo.services.i18n.spring.beans.propertyeditors Cal definir les següents propietats:
Segons el llenguatge de l'usuari, cerca si es troba com aaclau en el mapa. Si el troba, realitza el pas de tipus segons el patró definit al valor de la clau del mapa. Exemple:
<bean id="customEditors" class="java.util.HashMap"> <constructor-arg> <map> <entry key="java.util.Date"> <bean class="net.gencat.ctti.canigo.services.i18n.spring.beans.propertyeditors.CustomDateEditor"> <property name="i18nService" ref="i18nService"/> <property name="localeDatePatternsMap"> <map> <entry> <key><value>es</value></key> <value>dd/MM/yyyy</value> </entry> <entry> <key><value>es_ES</value></key> <value>dd/MM/yyyy</value> </entry> <entry> <key><value>ca_ES</value></key> <value>dd/MM/yyyy</value> </entry> <entry> <key><value>ca</value></key> <value>dd/MM/yyyy</value> </entry> <entry> <key><value>en</value></key> <value>MM/dd/yyyy</value> </entry> <entry> <key><value>en_GB</value></key> <value>MM/dd/yyyy</value> </entry> </map> </property> </bean> </entry> </map> </constructor-arg> </bean>
Per tal que funcioni correctament la transformació definirem el configurador d'editors. Classe: CustomEditorConfigurer I definirem les següents propietats:
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config. CustomEditorConfigurer"> <property name="customEditors"><ref local="customEditors"></ref></property> </bean> </beans> Configuració de les AccionsLa configuració de cadascuna de les nostres accions inclou 2 pasos:
Configuració Struts Fitxer de configuració: struts-config.xml Ubicació proposada: <PROJECT_ROOT>/src/main/resources/struts/struts-config.xml
A diferència de Struts, en la que hem de definir un formulari per cada pantalla, en canigo s'ofereix una classe 'SpringBindingActionForm' a utilitzar per les accions.
<form-bean name="actionForm" type="net.gencat.ctti.canigo.services.web.struts.
SpringBindingActionForm"/>
</form-beans>
La configuració de l'acció es realitza de la mateixa forma que Struts, pel que es recomana una lectura prèvia de Struts per a més detalls.
<action path="/categories" name="actionForm" scope="request" parameter="reqCode"> <forward name="error" path="pages.categoryEdit"/> <forward name="edit" path="pages.categoryEdit"/> <forward name="create" path="pages.categoryEdit"/> <forward name="list" path="pages.categories"/> <forward name="errorList" path="pages.categories"/> <forward name="success" redirect="true"/> </action> Configuració d'injecció de dependències Fitxer de configuració: action-servlet.xml Ubicació proposada: <PROJECT_ROOT>/src/main/resources/spring/action-servlet.xml Per cadascuna de les accions de Struts definides al fitxer 'struts-config.xml' injectarem propietats adicionals que podran ser usades des de l'acció (tal i com es realitza entre qualsevol objecte segons defineix el Servei de Configuració). Per tal que es pugui fer la injecció el id del bean ha de coincidir amb la propietat 'path' definida a l'acció dins el fitxer 'struts-config.xml'.
<bean id="/editAccount" class="net.gencat.ctti.canigo.samples.jpetstore.struts.action.AccountAction"> <property name="logService" ref="loggingService"/> <property name="serializationService" ref="xmlSerializationService"/> <property name="pojoClass" value="net.gencat.ctti.canigo.samples.jpetstore.model.Account" /> <property name="accountBO" ref="accountBO"/> <property name="defaultSuccessMessage" value="action.defaultSuccessMessage"/> <property name="tagsConfiguration"> </bean> En aquest exemple podem veure com injectar propietats en una acció. Algunes d'aquestes són serveis, altres objectes de negoci. N'hi ha que són comuns a totes les accions com pojoClass i defaultSuccessMessage. La primera indica el formulari que s'utilitzarà per a l'acció mentre que la segona permet introduïr missatges de confirmació per a l'acció executada. Els missatges de confirmació tenen el següent funcionament: S'especifica la clau i18n mitjançant la propietat defaultSuccessMessage, la qual tindrà que estar en el message-resources configurat en el fitxer struts-config.xml. Aquest serà el missatge generic per a totes les accions, independenment del reqCode, que s'utilitzarà si no es troba un clau i18n en el message-resources que cumpleixi el següent patró defaultSuccesMessage.reqCode. Per tant, primer es buscarà un missatge concret per a l'acció segons el seu reqCode. Si no es troba s'utilitzarà el missatge genèric, i si aquest no s'ha configurat o no es pot resoldre la clau especificada, no apareixerà missatge de confirmació en l'execució de l'acció. Pel que fa a la presentació del missatge, es tindrà que incloure la jsp success.jsp que s'inclou en la plantilla de projecte a Canigó.
<import resource="action-servlet-accounts.xml"/> <import resource="action-servlet-categories.xml"/> <import resource="action-servlet-products.xml"/> <import resource="action-servlet-items.xml"/> <import resource="action-servlet-mails.xml"/> <import resource="action-servlet-files.xml"/> ... UtilitzacióEines de SuportStruts Easy PluginAmb la instal- lació d'aquest plugin a Eclipse podem visualitzar de forma gràfica els nostres fitxers de configuració de Struts. Pàgina de descàrrega: Versió actual: 1.1.7 Tancar Eclipse i descomprimir el fitxer al directori d'instal- lació de eclipse.
|